/**
 * @file protocol.c
 * @Synopsis  这是整个系统的核心处理文件，主要做设备的通讯协议处理
 * 显示逻辑处理、按键、电池、GPRS模块等应用层处理逻辑。当前版本系统
 * 主要实现以下功能
 * 1. 设备定时向服务器发送02报文查询是否有更新事件。
 * 2. 设备根据查询事件类型，修改询问更新周期。
 * 3. 设备根据查询事件类型，下载图片并且刷新显示。
 * @author SWFighter
 * @version 1.0.0
 * @date 2019-01-02
 */
#include "protocol.h"
#include "appconfig.h"
#include "sysmanage.h"
#include "gprs.h"
#include "epd_show.h"


#ifdef USING_DEBUG_SERVER
char SERVER_IP[32] = "demo.nsqdz.com";
int SERVER_PORT     =  8090 ;
#else
char SERVER_IP[32]= "nsqdz.com";//"125.67.236.55"
int SERVER_PORT=       8099;
#endif
//static rt_timer_t epd_timer;


//rt_event_t update_evt = NULL;

#define UPDATE_EVT_SIZE   5
static u16_t updateEVT[UPDATE_EVT_SIZE] = {0};
u8_t elsPicBuf1[ELS_PIC_BUF_SIZE]={0};
static u8_t keyEvt = 0;


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  获取显示buf
 *
 * @Returns   
 */
/* ----------------------------------------------------------------------------*/
u8_t* show_buffer_get(void)
{
	return elsPicBuf1;
}

u8_t is_key_evt_wakeup(void)
{
	return keyEvt;
}

void set_key_evt_wakeup(void)
{
	keyEvt = 1;
	update_event_mail(PRO_EVT_KEY);
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  通知服务器修改完成 
 *
 * @Param type  修改时间的类型
 * @Param value 通知结果
 *
 * @Returns   
 */
/* ----------------------------------------------------------------------------*/
STATUS affirm_mod_finsh(u8_t type,u8_t *value)
{
	msgFinshModReqDef *modFReq;
	msgFinshModAckDef *modFAck;
	devInfodef *info;
	s8_t iresult;
	STATUS result;
	u16_t crc16;
	
	//分配资源
	modFAck = calloc(1, sizeof(msgFinshModAckDef));
	OS_ASSERT(modFAck);
	modFReq = calloc(1,sizeof(msgFinshModReqDef));
	OS_ASSERT(modFReq);
	info = devinfo_get();

	//准备数据
	modFReq->msg.cmd = Cmd_modFinshReq;
	modFReq->msg.type = type;
	uint32_to_str(info->mac,modFReq->msg.id);
	uint16_to_str(sizeof(*modFReq), modFReq->msg.len);
	crc16 = net_crc16(&modFReq->buf[2],sizeof(*modFReq)-4);//计算crc16
	uint16_to_str(crc16,modFReq->msg.crc);
	//建立链接
	//iresult = gsm_gprs_connect(1,SERVER_IP,SERVER_PORT,1000);//链接后台
	iresult = 0;
	if(iresult == 0)
	{
		//发送数据
		u16_t sendSize;
		u16_t recvSize;

		sendSize = sizeof(*modFReq);
		recvSize = sizeof(*modFAck);
		iresult = rsend_tcp_data(modFReq->buf, sendSize, modFAck->buf, &recvSize, 500);
		if(iresult == 0)//发送成功
		{
			//计算流量
			info->flow += (TCP_FIX_BNUM*2 + sendSize + recvSize);
			//解析数据
			if(modFAck->msg.cmd == Cmd_modFinshAck)//命令正确
			{
				printf("Mod result %d\n",modFAck->msg.result);
				(*value) = modFAck->msg.result;
				result = OK;
			}
			else
			{
				result = FAIL;
			}
		}
		else
		{
			result = FAIL;
		}
	}
	else
	{
		result = FAIL;
	}

	if(result != OK)//执行失败，断开链接
	{
		gsm_gprs_connect(0,SERVER_IP,SERVER_PORT,100);
	}

	free(modFAck);
	free(modFReq);

	return result;
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  从服务器获取设备睡眠周期
 *
 * @Returns   OK 获取成功  FAIL 获取失败 
 */
/* ----------------------------------------------------------------------------*/
STATUS server_mod_sleep(void)
{
	msgAskCycleReqDef *askCycleReq;
	msgAskCycleAckDef *askCycleAck;
	STATUS result = FAIL;
	s8_t iresult;
	devInfodef *info;
	//s8_t csq;//信号值
	u16_t crc16;

	//分配资源
	askCycleReq = calloc(1,sizeof(msgAskCycleReqDef));
	OS_ASSERT(askCycleReq)
	askCycleAck = calloc(1,sizeof(msgAskCycleAckDef));
	OS_ASSERT(askCycleAck)
	info = devinfo_get();

	//准备数据
	askCycleReq->msg.cmd = Cmd_askCycModReq;
	uint16_to_str(sizeof(msgAskCycleReqDef)-2, askCycleReq->msg.len);
	uint32_to_str(info->mac, askCycleReq->msg.id);
	crc16 = net_crc16(&askCycleReq->buf[2],sizeof(msgAskCycleReqDef)-4);//计算crc16
	printf("crc16 = %x\n",crc16);
	uint16_to_str(crc16, askCycleReq->msg.crc);
	
	//发送数据
	result = gprs_connet_resend(gsm_gprs_connect,1,(char *)info->url,info->port,1000);
	info->flow += TCP_CONNECT_BNUM;//计算链接流量
	if(result == OK)
	{
		u16_t recvSize;

		recvSize = sizeof(*askCycleAck);
		iresult = rsend_tcp_data(askCycleReq->buf,sizeof(*askCycleReq),askCycleAck->buf,&recvSize,500);
		info->flow += (TCP_FIX_BNUM*2+recvSize+sizeof(*askCycleReq));//计算流量
		if((iresult == 0)&&(recvSize > 4))
		{
			u16_t netCRC16;

			netCRC16 = net_crc16(&askCycleAck->buf[2], recvSize-4);
			crc16 = str_to_uint16(&askCycleAck->buf[recvSize-2]);
#ifndef USEING_NET_CRC16
			crc16 = netCRC16;
#endif
			if(crc16 == netCRC16)
			{
				if(askCycleAck->msg.cmd == Cmd_askCycModAck)//应答命令正确
				{
					u32_t time;
					u8_t finsh;
					u32_t *curCycle;
					u32_t oldCycle;
					u32_t curDate;
					u32_t modDate;

					printf("mod sleep\r\n");
					modDate = str_to_uint32(askCycleAck->msg.date); //修改时间
					date_show(modDate);//显示修改周期的时间点
					curDate = cur_date_show(); //系统当前时间
					printf("cur date %d\r\n",curDate);
					time = str_to_uint16(askCycleAck->msg.time);//服务器更新时间
					#ifdef USING_SEC_MODE
					#else
					time *= 60;//转换成秒钟
					#endif
					printf("mod sleep time = %d\r\n",time);
					curCycle = (u32_t*)update_ask_cycle_get();//睡眠时间
					oldCycle = *curCycle;
					if(time == 0)//静默模式
					{
						printf("System Silent Mode\n");
						(*curCycle) = (3600*24*365*5);//休眠5年
					}
					else//其他数字，表示休眠时间
					{
						(*curCycle) = time;
						printf("WebDate= %d CurDate= %d Difference= %d SleepCyclie = %d s\n",modDate,curDate,(curDate-modDate),time);
					}
				
					//发送完成请求
					result = affirm_mod_finsh(1,&finsh);//发送 修改完成 并且 关闭链接
					if(result == OK)//成功完成修改。
					{
						//更新模拟EEPROM中的保存数据
						info->cycle = (*curCycle);
						info->adjust = modDate;//保存起来用于同步更新周期
						result =	devinfo_save();//保存数据到Flash
						//调整本次睡眠周期
						if(*curCycle != 0)//除数不能为零，由于上面判断了所以不可能出现
						{
							u16_t surplus;
								
							info->cycle -= (curDate - modDate)%(*curCycle);//当前时间-上次修改的时间

							save_bkp_deep_sleep_value(info->cycle);//报调整后的睡眠值
							//计算剩余，
							surplus = info->cycle / EPS_MAX_DEELP_SLEEP;
							save_bkp_surplus_ask_num(surplus);
							printf("Surplus Wakeup Num %d\r\n",surplus);
						}
						
						if(info->cycle == 0 )//刚好这个时间点那么久不在调整
						{
							info->cycle = (*curCycle);
						}
						printf("Current This Update Cycle %d\n",info->cycle);
						set_system_stop_cycle(info->cycle);//(当前时间-修改时间)%更新周期(本次休眠时间)
						send_epd_mail(EPD_EVT_FULL);//事件查询
					}
					else//应答失败，服务器不知道改了所以不改。
					{
						(*curCycle) = oldCycle;
						printf("Mod Fail%s %s\n",__FUNCTION__,__LINE__);
					}
				}
				else//命令错误
				{
					printf("recv msg CMD error %x\n",askCycleAck->msg.cmd);
				}
			}
			else//crc错误
			{
				printf("recv msg CRC16 error %x != %x\n",crc16,netCRC16);
			}
		}
		else//发送失败
		{
			result =	FAIL;
		}
	}
	else//链接服务器失败
	{
		result = FAIL;
	}
	if(result != OK)//如果执行失败，断开连接
	{
		gsm_gprs_connect(0,(char *)info->url,info->port,100);
	}


	free(askCycleReq);
	free(askCycleAck);

	return result;
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  从服务器更新url 
 *
 * @Returns  OK 更新成功 
 */
/* ----------------------------------------------------------------------------*/
STATUS server_update_url(void)
{
	msgModUrlReqDef *msgReq;
	msgModUrlAckDef *msgAck;
	STATUS result = FAIL;
	s8_t iresult;
	devInfodef *info;
	s8_t csq;//信号值
	u8_t reboot = 0;
	u16_t crc16;//crc16

	info = devinfo_get();
	//分配资源
	msgReq = calloc(1,sizeof(msgModUrlReqDef));
	OS_ASSERT(msgReq)
	msgAck = calloc(1,sizeof(msgModUrlAckDef));
	OS_ASSERT(msgAck)
	

	//准备数据
	msgReq->msg.cmd = Cmd_modURLReq;
	uint16_to_str(sizeof(msgModUrlReqDef)-2, msgReq->msg.len);//长度=命令+数据+crc16
	uint32_to_str(info->mac, msgReq->msg.id);
	crc16 = net_crc16(&msgReq->buf[2],sizeof(*msgReq)-4);//计算CRC16
	uint16_to_str(crc16,msgReq->msg.crc);//填充CRC16
	
	//启动gsm
	iresult = gprs_module_start(&csq, 1);
	if(iresult != 0)//启动失败
	{
		free(msgReq);
		free(msgAck);
		printf("GSM Is Close %d\n",iresult);
		return FAIL;
	}
	
	//发送数据
	result = gprs_connet_resend(gsm_gprs_connect,1,(char *)info->url,info->port,1000);
	info->flow += TCP_CONNECT_BNUM;//计算链接流量
	if(result == OK)
	{
		u16_t recvSize;
		
		recvSize = sizeof(*msgAck);
		printf("recvSize = %d\n",recvSize);
		printf("sizeof(msgModUrlAckDef) = %d\n",sizeof(msgModUrlAckDef));
		printf("sizeof(modUrlAckDef) = %d\n",sizeof(modUrlAckDef));
		iresult = rsend_tcp_data(msgReq->buf,sizeof(*msgReq),msgAck->buf,&recvSize,500);
		printf("recvSize = %d\n",recvSize);
		info->flow += (TCP_FIX_BNUM*2+recvSize+sizeof(*msgReq));//计算流量
		if((iresult == 0) && (recvSize > 4))//接收数据长度要够，发送接收处理结果正常
		{
			u16_t netCRC16;
			
			crc16 = str_to_uint16(msgAck->msg.crc);//提出crc
			netCRC16 = net_crc16(&msgAck->buf[2],recvSize-4);
#ifndef USEING_NET_CRC16
			crc16 = netCRC16;
#endif
			if(crc16 == netCRC16)//crc校验成功
			{
				if(msgAck->msg.cmd == Cmd_modURLAck)//应答命令正确
				{
					u8_t finsh;
					
					info->port = str_to_uint16(msgAck->msg.port);
					memset(info->url, 0, 32);
					memcpy(info->url, msgAck->msg.url, strlen((const char *)msgAck->msg.url));
					printf("new url %s port %d %d\n",info->url,info->port,strlen((const char *)msgAck->msg.url));
				
					//发送完成请求
					result = affirm_mod_finsh(2,&finsh);//发送 修改完成 并且 关闭链接
					if(result == OK)
					{
						//保存重启设备
						result =	devinfo_save();
						if(result == OK)//保存成功
						{
							reboot = 1;
						}
					}
					else
					{
						printf("Mod url Fail%s %d\n",__FUNCTION__,__LINE__);
						result = FAIL;
					}
				}
				else//命令错误
				{
					printf("recv msg CMD error %x \n",msgAck->msg.cmd);
					result = FAIL;
				}
			}
			else//crc错误
			{
				printf("crc error %d != %d\n",crc16,netCRC16);
				result = FAIL;
			}
		}
		else//发送失败
		{
			result =	FAIL;
		}
	}
	else//链接服务器失败
	{
		result = FAIL;
	}
	
	if(result != OK)//下载失败断开链接
	{
		gsm_gprs_connect(0,(char *)info->url,info->port,100);
	}


	//释放资源
	free(msgReq);
	free(msgAck);

	if(reboot == 1)
	{
		sys_reboot();//重启系统
	}
	return result;
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  查询服务器是否有事件更新
 *
 * @Returns   OK 查询成功
 */
/* ----------------------------------------------------------------------------*/
STATUS dev_server_ask(void)
{
	msgAskEvtReqDef *askReq;
	msgAskEvtAckDef *askAck;
	s8_t iresult;
	STATUS result;
	devInfodef *info;
	u16_t crc16;

	//分配资源
	askReq = calloc(1,sizeof(msgAskEvtReqDef));
	OS_ASSERT(askReq);
	askAck = calloc(1,sizeof(msgAskEvtAckDef));
	OS_ASSERT(askAck);
	info = devinfo_get();
	result = OK;

	//启动GSM
	iresult = gprs_module_start(&(info->csq), 1);
	if(iresult != 0)//启动失败
	{
		free(askReq);
		free(askAck);
		printf("GSM Is Close %d\n",iresult);
		return FAIL;
	}
	//准备数据
	askReq->msg.cmd = Cmd_askEvtReq;
	askReq->msg.csq = info->csq;
	askReq->msg.vbat = info->vbat;
	uint16_to_str(sizeof(*askReq)-2, askReq->msg.len);
	uint32_to_str(info->flow, askReq->msg.flow);
	uint16_to_str(info->charge, askReq->msg.charge);
	uint32_to_str(info->mac, askReq->msg.id);
	crc16 = net_crc16(&askReq->buf[2],sizeof(msgAskEvtReqDef)-4);
	uint16_to_str(crc16, askReq->msg.crc);//填充crc16
	
	//链接服务器发送
	result = gprs_connet_resend(gsm_gprs_connect,1,(char *)info->url,info->port,1000);
	info->flow += TCP_CONNECT_BNUM;//计算链接流量
	if(result == OK)//链接成功
	{
		u16_t recvLen;

		recvLen = sizeof(*askAck);
		printf("send len=%d recv len=%d\n",sizeof(*askReq),sizeof(*askAck));
		iresult = rsend_tcp_data(askReq->buf,sizeof(*askReq),askAck->buf, &recvLen, 500);
		info->flow += (TCP_FIX_BNUM+recvLen+sizeof(*askReq));//统计流量
		if((iresult == 0) && (recvLen > 4))//接收数据成功
		{
			u16_t netCRC16;
			
			crc16 = str_to_uint16(askAck->msg.crc);//提出crc
			printf("crc16=%x\n",crc16);
			netCRC16 = net_crc16(&askAck->buf[2], recvLen-4);//计算crc16
#ifndef USEING_NET_CRC16
			crc16 = netCRC16;
#endif
			if(crc16 == netCRC16)//crc校验通过
			{
				if(askAck->msg.cmd == Cmd_askEvtAck)//命令正常
				{
					u32_t date;
					u32_t surplusValue;
					u16_t surplus;
					
					date = str_to_uint32(askAck->msg.date);
					//保存时间		，以服务器给出的时间为准		
					update_rtc_value(date);
					date_show(date);
					cur_date_show();

					//矫正睡眠唤醒时间
					if(info->adjust != 0)//设置过时间
					{
						surplusValue = info->cycle - (date - info->adjust)%(info->cycle);//当前时间-上次修改的时间
						
						save_bkp_deep_sleep_value(surplusValue);//报调整后的睡眠值
						//计算剩余，
						surplus = surplusValue / EPS_MAX_DEELP_SLEEP; //剩余时间由多少个71分钟组成
						save_bkp_surplus_ask_num(surplus);
						printf("Surplus Wakeup Num %d\r\n",surplus);
					}
					
					//分析事件
					if(askAck->msg.evt1 & Ask_URL)//更新url
					{
						update_event_mail(PRO_EVT_URL);
					}
					if((askAck->msg.evt1 & Ask_Gap)||(info->adjust == 0))//更新间隔
					{
						update_event_mail(PRO_EVT_UAT);
					}
					if(askAck->msg.evt1 & Ask_PIC)//更新图片
					{
						update_event_mail(PRO_EVT_KEY);
					}
					if(askAck->msg.evt1 & Ask_Upgrade)//更新图片
					{
						update_event_mail(PRO_EVT_UPA);
					}
				}
			}
			else//crc校验出错
			{
				printf("crc error %d != %d\n",crc16,netCRC16);
				result = FAIL;
			}
		}
		else//接收数据失败
		{
			result = FAIL;
		}
	}
	else
	{
		printf("link server fail\r\n");
		result = FAIL;
	}

	if(result != OK)//如果下载失败，断开链接
	{
		gsm_gprs_connect(0,(char *)info->url,info->port,100);
	}

	/*if(gsmclose == 1)//没有网络通讯了
	{
		gprs_module_stop();//GSM关机
	}*/
	
	//释放资源
	free(askReq);
	free(askAck);
	return result;
}

/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  向服务器注册新设备，获取设备ID
 *
 * @Returns   OK 注册成功 
 */
/* ----------------------------------------------------------------------------*/
STATUS dev_server_reg(void)
{
	msgDevRegReqDef *regReq;
	msgDevRegAckDef *regAck;
	s8_t iresult;
	STATUS result;
	devInfodef *info;
	u16_t crc16;

	iresult = -1;
	result = OK;
	info = devinfo_get();
	//分配资源
	regReq = calloc(1,sizeof(msgDevRegReqDef));
	OS_ASSERT(regReq);
	regAck = calloc(1,sizeof(msgDevRegAckDef));
	OS_ASSERT(regAck);

	//准备注册数据
	regReq->msg.cmd = Cmd_DevRegReq;
	regReq->msg.cpu = SYS_CPU_TYPE;
	regReq->msg.devType = PRODUCT_ID;
	regReq->msg.csq = info->csq;
	get_dev_mac(regReq->msg.id);
	regReq->msg.vbat = info->vbat;
	uint16_to_str(sizeof(msgDevRegReqDef)-2, regReq->msg.len);
	crc16 = net_crc16(&regReq->buf[2], sizeof(msgDevRegReqDef)-4);//计算crc
	uint16_to_str(crc16, regReq->msg.crc);
	printf("crc16 = %x\n",crc16);
	//启动gsm
	iresult = gprs_module_start(&(info->csq), 1);
	if(iresult != 0)//启动失败
	{
		//update_event_mail(PRO_EVT_REG);//重新注册,当没有网络的时候会陷入死循环

		//释放资源
		free(regAck);
		free(regReq);
		return FAIL;
	}
	printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%s\n",info->url);
	//发送、接受报文
	//iresult = gsm_gprs_connect(1,(char *)info->url,info->port,1000);//链接后台
	result = gprs_connet_resend(gsm_gprs_connect,1,(char *)info->url,info->port,1000);
	info->flow += TCP_CONNECT_BNUM;//计算链接流量
	if(result == OK)//链接成功
	{
		u16_t recvLen;

		recvLen = sizeof(*regAck);
		printf("recvLen=%d\n",recvLen);
		iresult = rsend_tcp_data(regReq->buf,sizeof(*regReq), regAck->buf, &recvLen, 500);
		info->flow += (recvLen+sizeof(*regReq)+TCP_FIX_BNUM);
		if((iresult == 0) && (recvLen > 4))//接收数据成功
		{
			u16_t netCRC16;
			
			//校验CRC
			crc16 = str_to_uint16(regAck->msg.crc);//取出crc
			printf("crc16 = %x\n",crc16);
			netCRC16 = net_crc16(&regAck->buf[2], recvLen-4);
#ifndef USEING_NET_CRC16
			crc16 = netCRC16;
#endif			
			if(crc16 == netCRC16)//CRC校验成功
			{
				if(regAck->msg.cmd == Cmd_DevRegAck)//命令正确
				{
					//u32_t date;
	
					//date = str_to_uint32(regAck->msg.date);
					//更新系统时间,改到查询函数同步时间
					switch(regAck->msg.result)//处理结果
					{
						case 0://成功
						case 1://设备已经过了注册
						{
							info->mac = str_to_uint32(regAck->msg.mac);
							info->regFlag = SYS_RegOne;//注册成功
							devinfo_save();
							printf("dev reg ok,get mac=%d\n",info->mac);
							result = OK;
							//注册成功后去查询事件。
							update_event_mail(PRO_EVT_ASK);
							break;
						}
						case 2://等待审核
						{
							result = FAIL;
							break;
						}
					}
				}
				else//命令错误
				{
					printf("recv net msg CMD error %x\n",regAck->msg.cmd);
					result = FAIL;
				}
			}
			else//校验失败
			{
				printf("recv net msg crc error %x != %x\n",crc16,netCRC16);
				result = FAIL;
			}
		}
		else//接收失败
		{
			result = FAIL;
			//处理重发
		}
	}
	else//链接失败
	{
		result = FAIL;
	}
	//解析注册数据

	if(result != OK)//下载失败，断开链接
	{
		gsm_gprs_connect(0,(char *)info->url,info->port,100);
	}

	
	//释放资源
	free(regAck);
	free(regReq);

	return result;
}

/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  服务器获取文件
 *
 * @Param type
 * @Param id
 * @Param bufSize
 *
 * @Returns   
 */
/* ----------------------------------------------------------------------------*/
s8_t get_server_file(u8_t type,u32_t id,u16_t bufSize)
{
	msgFileInfoReqDef *msgFileInfoReq;
	msgFileInfoAckDef msgFIA;
	msgFileDataReqDef msgFDR;
	msgFileDataAckDef *msgFDA;
	msgFileFinshReqDef msgFFQ;
	msgFileFinshAckDef msgFFA;
	u16_t size;
	u32_t fileID;
	u32_t fileSize;
	u16_t packNum;
	u8_t i;
	s8_t result;
	STATUS eresult;
	devInfodef *info;
	u16_t recvLen=0;
	u8_t reSendNum = 0;
	u16_t crc16;
	int timeout_value = 20;

	info = devinfo_get();	
	msgFDA = calloc(1, sizeof(msgFileDataAckDef));//文件数据请求应答
	OS_ASSERT(msgFDA);
	msgFileInfoReq = calloc(1, sizeof(msgFileInfoReqDef));
	OS_ASSERT(msgFileInfoReq);

	//链接服务器
	eresult = gprs_connet_resend(gsm_gprs_connect,1,(char *)info->url,info->port,1000);
	info->flow += TCP_CONNECT_BNUM;//计算链接流量
	if(eresult == OK)//连接服务器成功。
	{
		recvLen = sizeof(msgFileInfoAckDef);
		uint16_to_str(sizeof(msgFileInfoReqDef)-2,msgFileInfoReq->msg.len);
		msgFileInfoReq->msg.cmd = cmd_fileInfoReq;
		uint32_to_str(id,msgFileInfoReq->msg.id);
		uint16_to_str(bufSize,msgFileInfoReq->msg.size);//包大小
		msgFileInfoReq->msg.type =  type;

		//show_hex_string(&msgFileInfoReq->buf[2], sizeof(*msgFileInfoReq)-4);
		crc16 = net_crc16(&msgFileInfoReq->buf[2], sizeof(*msgFileInfoReq)-4);
		//printf("crc16 = %x %x\n",crc16,net_crc16("\x03\x00\x00\x00\x02\x01\x02\x00",8));
		
		uint16_to_str(crc16,msgFileInfoReq->msg.crc);//填充crc16
		
		size = sizeof(msgFileInfoReqDef);
		printf("send size:%d\n",size);
		result = rsend_tcp_data(msgFileInfoReq->buf,size,msgFIA.buf,&recvLen,500);//发送请求
		info->flow +=(TCP_FIX_BNUM*2+size+recvLen);//先统计流量
		if((result == 0) && (recvLen > 4))
		{
			u16_t netCRC16;

			netCRC16 = net_crc16(&msgFIA.buf[2], recvLen-4);
			crc16 = str_to_uint16(msgFIA.msg.crc);//提取crc16的值
			//memcpy(msgFIA.buf,hRecv, sizeof(msgFileInfoAckDef));
			#ifndef USEING_NET_CRC16
			crc16 = netCRC16;
			#endif
			if(crc16 == netCRC16)//crc16 校验成功
			{
				if(msgFIA.msg.cmd == 0x83)//命令正确
				{
					printf("cmd=%x\n",msgFIA.msg.cmd);
					fileID = str_to_uint32(msgFIA.msg.fileID);
					fileSize = str_to_uint32(msgFIA.msg.fileSize);
					packNum = str_to_uint16(msgFIA.msg.packNum);
					printf("fileID=%d\n",fileID);
					printf("fileSize=%d\n",fileSize);
					printf("packNum=%d\n",packNum);
				
					if(packNum*bufSize > ELS_PIC_BUF_SIZE)
					{
						packNum = ELS_PIC_BUF_SIZE/bufSize;
					}
				
					//开始传输数据包
					//memset(recv, 0, GSM_READ_LEN);
					//hRecv = recv;
					reSendNum = 0;//重发计数
					for(i=0; i<packNum;i++)
					{
						//u16_t recvLen;
						u16_t packPos;
						u16_t crc16;
				
						size = sizeof(msgFileDataReqDef);//发送长度
						recvLen = sizeof(msgFileDataAckDef);//接收长度
						printf("%d pack gprs send result=%d\n",i,result);
						//memset(recv, 0, GSM_READ_LEN);
						msgFDR.msg.cmd = Cmd_fileDataReq;//请求数据包
						uint16_to_str(sizeof(msgFDR)-2, msgFDR.msg.len);
						uint32_to_str(id, msgFDR.msg.devID);//设备ID
						uint32_to_str(fileID,msgFDR.msg.picID);//图片ID
						uint16_to_str(i, msgFDR.msg.pos);//图片包位置
						crc16 = net_crc16(&msgFDR.buf[2],size-4);
						uint16_to_str(crc16,msgFDR.msg.crc);//crc16
						
						result = rsend_tcp_data(msgFDR.buf,size,msgFDA->buf,&recvLen,1000);
						info->flow += (TCP_FIX_BNUM*2+size+recvLen);
						if((result == 0) && (recvLen > 4))//收发成功
						{
							u16_t netCRC16;
							//CRC校验
							crc16 = str_to_uint16(&msgFDA->buf[recvLen-2]);
							netCRC16 = net_crc16(&msgFDA->buf[2], recvLen-4);
#ifndef USEING_NET_CRC16
							crc16 = netCRC16;//没有使用CRC16
#endif
							if(netCRC16 == crc16)//包没有问题
							{
								//保存数据
								if(msgFDA->msg.cmd == Cmd_fileDataAck)
								{
									//memcpy(msgFDA->buf ,(const char *)recv, sizeof(msgFileDataAckDef));
									packPos = str_to_uint16(msgFDA->msg.pos);//包位置
									if(packPos*bufSize <= ELS_PIC_BUF_SIZE)
									{
										memcpy(&elsPicBuf1[packPos*bufSize],msgFDA->msg.data, bufSize);
									}
									else//文件太大
									{
										result = 1;
										break;
									}
								}
								else//失败
								{
									result = 2;
									break;
								}
							}
							else//crc错误接收有问题
							{
								if(reSendNum++ < 3)//上一包重发三次，每次还会重发三次，一个包发6次失败就不发了。
								{
									printf("crc16 error %x != %X resend %d\n",crc16,netCRC16,reSendNum);
									i--;
									continue;
								}
								else//不发了
								{
									result = 3;//crc错误
									reSendNum = 0;
									printf("crc16 error %x != %X \n",crc16,netCRC16);
									break;
								}
							}
						}
						else //没有收到应答。
						{
							if(reSendNum++ < 3)//上一包重发三次，每次还会重发三次，一个包发6次失败就不发了。
							{
								i--;
								continue;
							}
							else
							{
								result = 2;
								break;
							}
						}
					}
					if(i == packNum)//传输完成，发送应答
					{
						recvLen = sizeof(msgFileFinshAckDef);
						uint16_to_str(sizeof(msgFileFinshReqDef)-2,msgFFQ.msg.len);
						msgFFQ.msg.cmd = Cmd_fileFinshReq;
						msgFFQ.msg.result = result;//处理结果
						uint32_to_str(id, msgFFQ.msg.devID);
						uint32_to_str(type, msgFFQ.msg.picID);
						crc16 = net_crc16(&msgFFQ.buf[2],sizeof(msgFFQ)-4);
						uint16_to_str(crc16,msgFFQ.msg.crc);
						size = sizeof(msgFileFinshReqDef);
						rsend_tcp_data(msgFFQ.buf, size,msgFFA.buf,&recvLen,500);//发送05报文
						info->flow += (TCP_FIX_BNUM*2+size+recvLen);
					}
				}
				else//命令不对
				{
					static u8_t errnum=0;
				
					if( errnum++ == 1 )//三次不对可能是服务器地址错误
					{
						//SERVER_PORT = info->port;
						//strncpy((char *)info->url, "118.184.176.34", strlen("118.184.176.34"));
					}
					//printf("0x83 cmd error\n");
					result = -1;
				}
			}
			else//校验错误
			{
				printf("recv msg crc16 error %x != %x\n",crc16,netCRC16);
				result = -1;
			}
		}
		else//发送失败
		{
			printf("send msg fail!!!!\n");
		}
	}
	else//链接失败
	{
		result = -1;
		printf("connet sever fail...%d\n",result);
	}
	if(result != 0)//下载失败了，断开链接
	{
		gsm_gprs_connect(0,SERVER_IP,SERVER_PORT,100);
	}

	//释放资源	
	free(msgFileInfoReq);
	free(msgFDA);
	//free(recv);
	
	return result;
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis 请求报文事件
 *
 * @Param evt 事件
 */
/* ----------------------------------------------------------------------------*/
void update_event_mail(u16_t value)
{
	sendEvtProcess(updateEVT, UPDATE_EVT_SIZE, value);
}



/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  按键按下有效超时处理
 *
 * @Param arg 备用参数
 */
/* ----------------------------------------------------------------------------*/
void key_evnet_timeout(void *arg)
{

}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  按键中断处理
 *
 * @Param arg
 */
/* ----------------------------------------------------------------------------*/
void key_event_process(void *arg)
{
	
}




/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  显示器更新事件处理
 *
 * @Param arg
 */
/* ----------------------------------------------------------------------------*/
void epd_timer_process(void *arg)
{
	
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  启动epd定时器
 */
/* ----------------------------------------------------------------------------*/
void epd_timer_start(void)
{

}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  停止epd定时器
 */
/* ----------------------------------------------------------------------------*/
void epd_timer_stop(void)
{	

}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  epd定时器初始化
 */
/* ----------------------------------------------------------------------------*/
void epd_timer_init(void)
{

}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  从服务器更新图片
 *
 * @Param err 更新结果
 * @Param evt 事件
 *
 * @Returns   
 */
/* ----------------------------------------------------------------------------*/
STATUS update_server_pic(u8_t *err,u32_t evt)
{
	devInfodef *info;
	s8_t result;
	u8_t run;

	//先显示设备ID
	if(is_key_evt_wakeup() == 1)
	{
		//send_epd_mail(EPD_EVT_FULLID);//显示带ID图片
	}

	epd_timer_start();//启动下周提示寄存器
	info = devinfo_get();
	result = gprs_module_start(&(info->csq),1);
	printf("gprs_module_start() result = %d\n",result);
	if(result != 0)//启动失败
	{
		epd_timer_stop();
		if(result == -2)//没插卡
		{
			send_epd_mail(EPD_EVT_FULL);//事件查询
			return CANCEL;
		}
		else//其他异常
		{
			(*err)++;
			if((*err) < GSM_START_ERR_MAX)
			{
				update_event_mail(evt);
			}
			send_epd_mail(EPD_EVT_FULL);//事件查询
			return FAIL;
		}
	}
	else
	{
		(*err) = 0;
	}
	
	//下载3次，又一次成功就退出
	run = 3;
	do
	{
		if(info->regFlag != SYS_RegFinsh)//没有完成注册
		{
			result = get_server_file(3,info->mac,512);
		}
		else
		{
			result = get_server_file(1,info->mac,512);
		}
		
		if(result == 0)//下载成功
		{
			update_event_mail(PRO_EVT_ASK);//询问
			break;
		}
	}while(run--);
	//gprs_module_stop();
	epd_timer_stop();
	keyEvt = 0;//清除本次按键唤醒
	if(result == 0)//数据更新成功
	{
		printf("save data start...\n");
		cur_date_show();
		send_epd_mail(EPD_EVT_BUFFULL);//事件查询
		eeprom_save_data(elsPicBuf1);
		save_bkp_wakeup_num(0);
		if(info->regFlag == SYS_RegOne)//第一次注册下载的图片作为ID
		{
			info->regFlag = SYS_RegFinsh;
			eeprom_save_IDdata(elsPicBuf1);//保存第一张图
			devinfo_save();//保存参数
		}
		printf("save data finsh\n");
		cur_date_show();
	}
	else//更新失败，显示原来的图片
	{
		send_epd_mail(EPD_EVT_FULL);
		return FAIL;
	}

	return OK;
}


static void set_default_ap_config(void)
{
	struct station_config * config = (struct station_config *)zalloc(sizeof(struct
	station_config));

	wifi_set_opmode(STATION_MODE);
	config->bssid_set = 0;
	strcpy(config->ssid, "ELS_AP");
	strcpy(config->password, "nsq123456");
	wifi_station_set_config(config);
	//wifi_station_set_config_current(config);
	free(config);
	printf("set default ap config\r\n");
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  设备信息初始化处理
 *
 * @Returns   
 */
/* ----------------------------------------------------------------------------*/
STATUS devinfo_init_process(void)
{
	STATUS result = OK;

	result = devinfo_loader();
	if(result == OK)//加载成功
	{
		devInfodef *devInfo;
		devInfo = devinfo_get();
		printf("devInfo->mac       = %d\r\n",devInfo->mac);
		printf("devInfo->regFlag   = %d\r\n",devInfo->regFlag);
		printf("devInfo->url       = %s\r\n",devInfo->url);
		printf("devInfo->port      = %d\r\n",devInfo->port);
		printf("devInfo->vbat      = %d \%\r\n",devInfo->vbat);
		printf("devInfo->save      = %X\r\n",devInfo->save);
		printf("devInfo->cycle     = %d S\r\n",devInfo->cycle);
		printf("devInfo->adjust    = %d S\r\n",devInfo->adjust);
		if(devInfo->save == DEV_INIT_SAVE_FLAGE)//已经保存
		{
			if(devInfo->regFlag == SYS_RegNone)//没有注册要通知设备注册
			{
				update_event_mail(PRO_EVT_REG);//发送注册事件
			}
			printf("devInfo->cycle = %d\n",devInfo->cycle);
			set_system_stop_cycle(devInfo->cycle);//更新停机休眠时间。
			//devInfo->sleep++;
			//devinfo_save();
		}
		else//第一次运行
		{
			devInfo->mac = 0xffffffff;
			printf("mac:%d",devInfo->mac );
			devInfo->regFlag = SYS_RegNone;
			devInfo->flow = 0;//初始化流量
			devInfo->charge = 0;//初始化充电次数
			devInfo->port = SERVER_PORT;//默认端口
			devInfo->cycle = RTC_ALARM_WAKEUP_TIME;//默认
			devInfo->adjust = 0;//默认就是0
			memset(devInfo->url,0,32);
			memcpy(devInfo->url, SERVER_IP, strlen(SERVER_IP));
			devInfo->save = DEV_INIT_SAVE_FLAGE;
			devinfo_set(devInfo);
			result = devinfo_save();
			if(result != OK)
			{
				printf("sys eeprom save data error %d\n",__LINE__);
				vTaskDelay(10 / portTICK_RATE_MS);
			}
			printf("eeprom save ok\n");
			set_bkp1_reg(0);
			save_bkp_askfail_num(0);//查询寄存器初始化0次
			set_default_ap_config();//设置默认WIFI
			sys_reboot();
		}
	}

	return result;
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  获取本次休眠时间
 *
 * @Param info 设备信息
 */
/* ----------------------------------------------------------------------------*/
static u32_t get_this_sleep_time(devInfodef *info)
{
	u32_t curDate;
	u32_t cycle;
	
	if(info->adjust != 0)//没有修改过休眠周期
	{
		curDate = cur_date_show(); //系统当前时间
		cycle = info->cycle-((curDate - info->adjust)%(info->cycle));//当前时间-上次修改的时间
		printf("curDate=%d info->adjust=%d info->cycle=%d\n",curDate,info->adjust,info->cycle);//
		if(cycle != 0)//周期可调
		{
			if(cycle < 5)//快了5S
			{
				printf("old adjust sleep time %d\n",cycle);
				cycle += info->cycle;
			}
			printf("adjust sleep time %d\n",cycle);
			return cycle;	
		}
	}

	return info->cycle;
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  查询服务器结果事件
 *
 * @Param err
 */
/* ----------------------------------------------------------------------------*/
void ask_evt_result_process(STATUS err)
{
	//这个函数没调用一次RAM都会丢失所以只能用备份寄存器
	static u16_t cnt=0;
	devInfodef *info;
	u32_t cycle;

	cnt = load_bkp_askfail_num();//查询服务器失败的次数
	info = devinfo_get();//获取设备参数
	if(err == OK)//询问成功
	{
		cycle = get_this_sleep_time(info);
		set_system_stop_cycle(cycle);
		if(get_rtc_system_event_bit(EVT_NET_EXP) == TRUE)//上次网络异常，刷新屏幕
		{
			set_rtc_system_event_bit(EVT_NET_EXP,FALSE);//清除
			send_epd_mail(EPD_EVT_FULL);//事件查询
		}
		else if(((cnt != 0)&&(cnt >= 3))|| (get_rtc_system_event_bit(EVT_NOAP_HINT)))//网络第一次恢复正常。
		{
			set_rtc_system_event_bit(EVT_NOAP_HINT,FALSE);//不能连接路由器直接提示标记清除
			send_epd_mail(EPD_EVT_FULL);//刷新屏幕
		}
		cnt = 0;//失败次数增加
	}
	else if(err == CANCEL)//没插卡不做特殊处理
	{
		cycle = get_this_sleep_time(info);
		set_system_stop_cycle(cycle);
	}
	else//询问失败
	{
		cnt++;
		if(cnt == 3)//连上路由器没有网络，或者连上后网络断开,三次这样显示异常
		{
			send_epd_mail(EPD_EVT_SIMAlA);//显示连不上基站
		}
		printf("link error num %d\n",cnt);
		if((cnt < PROCESS_ERR_MAX)&&((cnt*ERR_SLEEP_CYCLE)<=info->cycle))//处理事件失败，递增尝试
		{
			printf("Next Update time %d\n",(cnt*ERR_SLEEP_CYCLE));
			set_system_stop_cycle(cnt*ERR_SLEEP_CYCLE);
		}
		else//不需要尝试了
		{
			cycle = get_this_sleep_time(info);
			set_system_stop_cycle(cycle);
		}
	}
	save_bkp_askfail_num(cnt);
}


/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  自动同步更新周期，主要用于新设备
 */
/* ----------------------------------------------------------------------------*/
void aoto_sync_cycle(void)
{
	devInfodef *info;	

	info = devinfo_get();
	if(info->regFlag == SYS_RegOne)//注册成功后
	{
		if(info->cycle == RTC_ALARM_WAKEUP_TIME)
		{
			update_event_mail(PRO_EVT_UAT);
		}
	}

}


void reloadFlashPicShow(u8_t day)
{
	u16_t value = 0;
	devInfodef *info;

	info = devinfo_get();
	
	value = load_bkp_wakeup_num();
	if((value*info->cycle)>(3600*24*day))//五天没更新
	{
		value = 0;
		send_epd_mail(EPD_EVT_FULL);//刷新图片
		printf("reload Flash Pic Show\r\n");
	}
	value++;
	save_bkp_wakeup_num(value);
}



/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  核心业务协议处理线程
 *
 * @Param arg
 */
/* ----------------------------------------------------------------------------*/
void ICACHE_FLASH_ATTR
protocol_thread_entry(void *arg)
{
	//加载系统配置信息
	//查询服务器
	devInfodef *info;
	u8_t test;
	u8_t updateErr = 0;
	u8_t update_app = 0;

	printf("Host Name %s\r\n",wifi_station_get_hostname());
	vbat_init_process();

	update_event_mail(PRO_EVT_ASK);

	reloadFlashPicShow(15);//15天没有刷新就自动刷新，位置显示效果
	while(1)
	{
		u16_t  evt;
		//system_soft_wdt_restart();

		entry_work_task(PROT_TASK_WORK);
		evt = EvtRecvProcess(updateEVT, UPDATE_EVT_SIZE);
		if(evt != 0)
		{
			devInfodef *info;

			info = devinfo_get();
			printf("recv event %x reg =%d mac=%d == ",evt,info->regFlag,info->mac);
			if((evt & PRO_EVT_KEY) && (info->regFlag > SYS_RegNone))//按键强制更新,已经注册了才可以
			{
				STATUS result;
				
				printf("PRO_EVT_KEY\n");
				result = update_server_pic(&updateErr,evt);
				ask_evt_result_process(result);//事件结果处理优化
			}
			if((evt & PRO_EVT_ASK) && (info->regFlag > SYS_RegNone))//rtc自动更新，已经注册了才可以
			{
				STATUS result;
				
				printf("PRO_EVT_ASK\n");
				result = dev_server_ask();//设备查询服务器
				ask_evt_result_process(result);//事件结果处理优化
			}
			if(evt & PRO_EVT_REG)//注册设备
			{
				printf("PRO_EVT_REG\n");
				dev_server_reg();
			}
			if(evt & PRO_EVT_UAT)
			{
				printf("PRO_EVT_UAT\n");
				server_mod_sleep();
			}
			if(evt & PRO_EVT_URL)
			{
				printf("PRO_EVT_URL\n");
				server_update_url();
			}
			if(evt & PRO_EVT_UPA)
			{
				printf("PRO_EVT_UPA\n");	
				ota_start_Upgrade(SERVER_IP,80,"upload/firmware/213wifi/");//测试
				update_app = 1;
			}
		}
		else
		{
			//系统进入休眠模式
			exit_work_task(PROT_TASK_WORK);
			#ifdef USING_PowerManage
			if(is_entry_sleep() == 0)//可以睡眠
			{
				printf("entry sleep\r\n");
				//system_print_meminfo();
				system_entry_deep_sleep(0);
			}
			#endif
			if(update_app == 0)
			{
				wifi_station_disconnect();//关闭WIFI
			}
		}
		vTaskDelay(10 / portTICK_RATE_MS);
	}
	vTaskDelete(NULL);
}

/* --------------------------------------------------------------------------*/
/**
 * @Synopsis  核心线程初始化
 *
 * @Returns   
 */
/* ----------------------------------------------------------------------------*/
int protocol_thread_init(void)
{
	epd_timer_init();

	xTaskCreate(protocol_thread_entry, "proto", 1024, NULL, 1, NULL);

	return 0;
}



